package net.xiduth.game.player.content.grandexchange;

import java.io.Serializable;
import java.text.NumberFormat;

import net.xiduth.game.World;
import net.xiduth.game.item.Item;
import net.xiduth.game.player.Player;
import net.xiduth.game.player.content.ItemConstants;
import net.xiduth.game.player.content.exchange.ItemOffer.OfferType;
import net.xiduth.utils.ChatColors;
import net.xiduth.utils.ItemExamines;

/**
 * This class handles all of the actions in the grand exchange, excluding the
 * processing of world offers which will be ran on an executable thread.
 * 
 * @author Tyluur <itstyluur@gmail.com>
 * @since August 17th, 2012
 */
public class GrandExchange implements Serializable, ProgressBars {

	private static final long serialVersionUID = 6594715911979400616L;

	private static final int MAIN_INTERFACE = 105,

			SELL_INTERFACE = 107;		

	/**
	 * The array of the player's grand exchange offers
	 */
	private GrandExchangeOffer[] offers;

	/**
	 * The instance of the player object in this class.
	 */
	private Player player;

	/**
	 * Creates a new GrandExchange constructor for the player instance.
	 * 
	 * @param player
	 *            The player instance.
	 */
	public GrandExchange(Player player) {
		this.player = player;
		offers = new GrandExchangeOffer[6];
	}

	/**
	 * This method handles the clicking of buttons on all of the Grand Exchange
	 * player interfaces.
	 * 
	 * @param interfaceId
	 *            The interface id supplied from the client.
	 * @param buttonId
	 *            The button id supplied from the client as an incoming packet.
	 * @param packetId
	 *            The packetId sent to the server from the client.
	 * @param slotId
	 *            The slotId clicked on.
	 * @param slotId2
	 *            The slotId2 (this is an item in most cases);
	 */
	public void handleButtonEvent(int interfaceId, int buttonId, int packetId,
			int slotId, int slotId2) {
		final GrandExchangeOffer offer;
		switch(interfaceId) {
		case MAIN_INTERFACE:
			if (player.getAttributes().get("offer_loading") != null) {
				player.sendMessage("Your grand exchange offers are currently processing; please wait...");
				return;
			}
			for (int i = 0; i < WorldOffers.BUY_BUTTON_IDS.length; i++) {
				if (buttonId == WorldOffers.BUY_BUTTON_IDS[i]) {
					player.getAttributes().put("grand_exchange_slot", getSlot(buttonId));
					sendBuyScreen();
					return;
				}
			}
			for (int i = 0; i < WorldOffers.SELL_BUTTON_IDS.length; i++) {
				if (buttonId == WorldOffers.SELL_BUTTON_IDS[i]) {
					player.getAttributes().put("grand_exchange_slot", getSlot(buttonId));
					sendSellScreen();
					return;
				}
			}
			for (int i = 0; i < WorldOffers.COLLECT_BUTTON_IDS.length; i++) {
				if (buttonId == WorldOffers.COLLECT_BUTTON_IDS[i]) {
					player.getAttributes().put("grand_exchange_slot", getSlot(buttonId));
					player.getDialogueManager().startDialogue("GrandExchangeCollect", getSlot(buttonId));
					return;
				}
			}
			switch(buttonId) {
			case 157:
			case 160:
				offer = (GrandExchangeOffer) player.getAttributes().get("grand_exchange_offer");
				if (offer.getOfferedAmount() + 1 > Integer.MAX_VALUE) {
					player.sendMessage("You cannot buy that many...");
					return;
				}
				offer.setOfferedAmount(offer.getOfferedAmount() + 1);
				player.getPackets().sendConfig(1110, offer.getOfferedAmount());
				break;
			case 162:
				offer = (GrandExchangeOffer) player.getAttributes().get("grand_exchange_offer");
				if (offer.getOfferedAmount() + 10 > Integer.MAX_VALUE) {
					player.sendMessage("You cannot buy that many...");
					return;
				}
				offer.setOfferedAmount(offer.getOfferedAmount() + 10);
				player.getPackets().sendConfig(1110, offer.getOfferedAmount());
				break;
			case 164:
				offer = (GrandExchangeOffer) player.getAttributes().get("grand_exchange_offer");
				if (offer.getOfferedAmount() + 100 > Integer.MAX_VALUE) {
					player.sendMessage("You cannot buy that many...");
					return;
				}
				offer.setOfferedAmount(offer.getOfferedAmount() + 100);
				player.getPackets().sendConfig(1110, offer.getOfferedAmount());
				break;
			case 181:
			case 175:
			case 177:
			case 179:
				player.getDialogueManager().startDialogue("SimpleMessage", "You cannot change the price of the offer...");
				break;
			case 168:
				player.getPackets().sendRunScript(108, new Object[] { "How many would you like to buy?" });
				player.getAttributes().put("grand_exchange_x", true);
				break;
			case 166:
				offer = (GrandExchangeOffer) player.getAttributes().get("grand_exchange_offer");
				switch(offer.getType()) {
				case BUY:
					if (offer.getOfferedAmount() + 1000 > Integer.MAX_VALUE) {
						player.sendMessage("You cannot buy that many...");
						return;
					}
					offer.setOfferedAmount(offer.getOfferedAmount() + 1000);
					player.getPackets().sendConfig(1110, offer.getOfferedAmount());
					break;
				case SELL:
					if (player.getInventory().containsItem(offer.getItem().getDefinitions().getCertId(), 1)) {
						offer.getItem().setId(offer.getItem().getDefinitions().getCertId());
						player.getAttributes().put("note_item", offer);
					}
					offer.setOfferedAmount(player.getInventory().getNumerOf(offer.getItem().getId()));
					if (player.getAttributes().get("note_item") != null && player.getAttributes().get("note_item").equals(offer)) {
						offer.getItem().setId(offer.getItem().getId() - 1);
					}
					break;
				}
				player.getPackets().sendConfig(1110, offer.getOfferedAmount());
				break;
			case 128:
				resetInterfaceConfigs();
				sendExchangeScreen();
				player.getInterfaceManager().closeInventory();
				player.getInterfaceManager().sendInventory();
				final int lastGameTab = player.getInterfaceManager().openGameTab(9); // friends
				player.setCloseInterfacesEvent(new Runnable() {
					@Override
					public void run() {
						player.getInterfaceManager().sendInventory();
						player.getInventory().unlockInventoryOptions();
						player.getInterfaceManager().sendEquipment();
						player.getInterfaceManager().openGameTab(lastGameTab);
					}
				});
				break;
			case 155:
				offer = (GrandExchangeOffer) player.getAttributes().get("grand_exchange_offer");
				if (offer.getOfferedAmount() - 1 < 1) {
					player.sendMessage("0 is an invalid amount for an offer.");
					return;
				}
				offer.setOfferedAmount(offer.getOfferedAmount() - 1);
				player.getPackets().sendConfig(1110, offer.getOfferedAmount());
				break;
			case 190:
				sendBuyScreen();
				break;
			case 186:
				offer = (GrandExchangeOffer) player.getAttributes().get("grand_exchange_offer");
				if (offer.getOfferedPrice() > Integer.MAX_VALUE ||
						offer.getOfferedPrice()  == Integer.MAX_VALUE ||
						offer.getOfferedPrice() >= Integer.MAX_VALUE ||
						offer.getOfferedPrice() < 0) {
					player.getPackets().sendGameMessage("The price of the item is too high!");
					return;
				}
				if ((offer.getOfferedPrice() == 0 || offer.getOfferedAmount() == 0 || offer.getOfferedPrice() * offer.getOfferedAmount() == 0)) {
					player.getPackets().sendGameMessage("Invalid amount.");
					return;
				}
				switch(offer.getType()) {
				case BUY:
					if(offer.isFinished()){
						return;
					}
					if (player.getInventory().getNumerOf(995) < offer.getOfferedPrice()
							&& player.getMoneyInPouch() < offer.getOfferedPrice()) {
						player.sendMessage("You need " + NumberFormat.getIntegerInstance().format(offer.getOfferedPrice()) + " coins to buy this item.");
						return;
					}
					if (player.getMoneyInPouch() > offer.getOfferedPrice()) {
						player.getMoneyPouch().remove(offer.getOfferedPrice());
					} else if (player.getInventory().getNumerOf(995) > offer.getOfferedPrice()) {
						player.getInventory().deleteItem(995, offer.getOfferedPrice());
					}
					getOffers()[(Integer) player.getAttributes().get("grand_exchange_slot")] = offer;
					WorldOffers.getOffers().add(offer);
					sendExchangeScreen();
					break;
				case SELL:
					System.out.println(offer.getItem().getId());
					if(offer.getItem().getId() == 995){
						player.getPackets().sendGameMessage("You can't sell that item!");
					}
					if (player.getInventory().containsItem(offer.getItem().getDefinitions().getCertId(), 1)) {
						offer.getItem().setId(offer.getItem().getDefinitions().getCertId());
						player.getAttributes().put("noting_item", offer);
					}
					if (offer.getOfferedAmount() > player.getInventory().getNumerOf(offer.getItem().getId())) {
						player.sendMessage("<col=FF0000>You don't have that many to sell!");
						return;
					}
					if (player.getInventory().containsItem(offer.getItem().getId(), offer.getOfferedAmount())) {
						player.getInventory().deleteItem(offer.getItem().getId(), offer.getOfferedAmount());
						if (player.getAttributes().get("noting_item") != null && player.getAttributes().get("noting_item").equals(offer)) {
							offer.getItem().setId(offer.getItem().getId() - 1);
						}
						getOffers()[(Integer) player.getAttributes().get("grand_exchange_slot")] = offer;
						sendExchangeScreen();
						WorldOffers.getOffers().add(offer);
					}
					break;
				}
				break;
			default:
				System.out.println("Unhandled ge button - " + buttonId);
			}
			break;
		case SELL_INTERFACE:
			Item itemToSell = new Item(slotId2);
			if (!ItemConstants.isTradeable(itemToSell) || itemToSell.getId() == 995) {
				player.sendMessage("You cannot sell that item.");
				return;
			}
			if (itemToSell.getDefinitions().isNoted()) {
				itemToSell.setId(itemToSell.getDefinitions().getCertId());
			}
			offer = new GrandExchangeOffer(player, itemToSell, (Integer) player.getAttributes().get("grand_exchange_slot"), OfferType.SELL, 1, itemToSell.getDefinitions().getValue(), 0);
			offer.getOwner().getPackets().sendConfig(1109, offer.getItem().getId());
			offer.getOwner().getPackets().sendConfig(1110, 1);
			offer.getOwner().getPackets().sendConfig(1114, offer.getOfferedPrice());
			offer.getOwner().getPackets().sendConfig(1115, offer.getOfferedPrice());
			offer.getOwner().getPackets().sendConfig(1116, offer.getOfferedPrice());
			offer.getOwner().getPackets().sendConfig(1111, offer.getOfferedPrice());
			offer.getOwner().getPackets().sendIComponentText(105, 143, ItemExamines.getExamine(itemToSell));
			player.getAttributes().put("grand_exchange_offer", offer);
			break;
		}
	}

	public void updatePlayer() {
		if (World.getPlayers().contains(player)) {
			player.sendMessage("One or more of your grand exchange offers have been updated.");
			if (player.getInterfaceManager().containsInterface(MAIN_INTERFACE))
				sendExchangeScreen();
		}
	}

	public void sendExchangeScreen() {
		player.getPackets().sendConfig(563, 4194304);
		player.getPackets().sendConfig(1112, -1);
		player.getPackets().sendConfig(1113, -1);
		player.getPackets().sendConfig(1109, -1);
		player.getPackets().sendConfig(1110, 0);
		player.getInterfaceManager().sendInterface(MAIN_INTERFACE);
		player.getPackets().sendUnlockIComponentOptionSlots(MAIN_INTERFACE, 209, -1, -1, 1, 2, 3, 5, 6);
		player.getPackets().sendUnlockIComponentOptionSlots(MAIN_INTERFACE, 211, -1, -1, 1, 2, 3, 5, 6);
		for (GrandExchangeOffer offers : player.getGrandExchange().getOffers()) {
			if (offers == null) continue;
			if (!WorldOffers.getOffers().contains(offers)) {
				player.sendMessage("<col=" + ChatColors.PURPLE + ">Offer [" + (offers.getSlot() + 1) + "/" + offers.getType().name() + "]</col> is not loaded in the world offers, please re-do this.");
			}
			boolean finished = offers.getAmountCompleted() == offers.getOfferedAmount();
			switch(offers.getType()) {
			case BUY:
				player.getPackets().sendGrandExchangeBar(player, offers.getSlot(), finished ? 5 : BUY_PROGRESS, offers.getItem().getId(), offers.getOfferedPrice(), offers.getOfferedAmount(), offers.getAmountCompleted());
				break;
			case SELL:
				player.getPackets().sendGrandExchangeBar(player, offers.getSlot(), finished ? 13 : SELL_PROGRESS, offers.getItem().getId(), offers.getOfferedPrice(), offers.getOfferedAmount(), offers.getAmountCompleted());
				break;
			}
		}
	}
	private void sendSellScreen() {
		resetInterfaceConfigs();
		player.getPackets().sendConfig(1113, 1);
		player.getInterfaceManager().sendInventoryInterface(107);
		final Object[] params = new Object[]{ "", "", "", "", "Offer", -1, 0, 7, 4, 93, 7012370 };
		player.getPackets().sendRunScript(149, params);
		player.getPackets().sendItems(93, player.getInventory().getItems());
		player.getPackets().sendHideIComponent(107, 0, false);		
		player.getPackets().sendIComponentSettings(107, 18, 0, 27, 1026);
		player.getPackets().sendConfig(1112, (Integer) player.getAttributes().get("grand_exchange_slot"));
		player.getPackets().sendHideIComponent(105, 196, true);
	}

	public void sendBuyScreen() {
		resetInterfaceConfigs();
		sendSearchScript();
	}

	/**
	 * Resets the Configurations of the InterfacePacket.
	 * 
	 * @param player
	 *            The Owner.
	 */
	private void resetInterfaceConfigs() {
		player.getPackets().sendConfig2(1109, -1);
		player.getPackets().sendConfig2(1110, 0);
		player.getPackets().sendConfig2(1111, 0);
		player.getPackets().sendConfig2(1112, -1);
		player.getPackets().sendConfig2(1113, 0);
	}

	/**
	 * Sends the search script appropriately.
	 */
	private void sendSearchScript() {
		player.getPackets().sendConfig(1109, -1);
		player.getPackets().sendConfig(1112, 0);
		player.getPackets().sendConfig(1113, 0);
		player.getPackets().sendConfig1(1241, 16750848);
		player.getPackets().sendConfig1(1242, 15439903);
		player.getPackets().sendConfig1(741, -1);
		player.getPackets().sendConfig1(743, -1);
		player.getPackets().sendConfig1(744, 0);
		player.getPackets().sendInterface(true, 752, 7, 389);
		player.getPackets().sendRunScript(570, new Object[] { "Grand Exchange Item Search" });
	}


	/**
	 * Gets the Box Slot id by switching the buttons,<br>	
	 * </br> Also helps you to figure the box slot configuration value.
	 * 
	 * @param buttonId
	 * @return Slot id.
	 */
	private int getSlot(int buttonId) {
		switch (buttonId) {
		case 31:
		case 32:
		case 19:
			return 0;
		case 47:
		case 35:
		case 48:
			return 1;
		case 63:
		case 51:
		case 64:
			return 2;
		case 82:
		case 83:
		case 70:
			return 3;
		case 101:
		case 102:
		case 89:
			return 4;
		case 120:
		case 108:
		case 121:
			return 5;
		default:
			return -1;
		}
	}

	public GrandExchangeOffer[] getOffers() {
		return offers;
	}

	public void setOffers(GrandExchangeOffer[] offers) {
		this.offers = offers;
	}
}
